﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SQLite;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Ventuz.OSC;
using System.Net;
using System.Net.Sockets;
using Vrpn;
using System.Runtime.InteropServices;

namespace VRPN_OSC_Gateway
{
    public partial class MainForm : Form
    {
        bool state = false;
        UdpWriter oscWriter;
        //Entities entities;
        List<RemoteHandler> remoteHandlers;

        public MainForm()
        {
            InitializeComponent();
            backgroundWorker.WorkerSupportsCancellation = true;
            this.configurationsTableAdapter.Fill(this.dataSet1.Configurations);
            this.sensorsTableAdapter.Fill(this.dataSet1.Sensors);
            this.vRPNServersTableAdapter.Fill(this.dataSet1.VRPNServers);
            this.oSCServersTableAdapter.Fill(this.dataSet1.OSCServers);
            this.sensorTypesTableAdapter.Fill(this.dataSet1.SensorTypes);
        }

        private void changeState(bool newstate)
        {
            if (state == newstate) // restart
            {
                changeState(!newstate);
            }
            if (newstate == true)
            {
                if (!initOsc()) return;
                if (!initVrpn()) return;
                configurationBindingSource.EndEdit();
                configurationsTableAdapter.Update(this.dataSet1.Configurations);
                bindingNavigator1.Enabled = false;
                dataGridView1.Enabled = false;
                showTrackingData.Enabled = false;
                updateIntervalTextBox.Enabled = false;
                oscUrl.Enabled = false;
                vrpnUrl.Enabled = false;
                backgroundWorker.RunWorkerAsync(remoteHandlers);
            }
            if (newstate == false)
            {
                bindingNavigator1.Enabled = true;
                dataGridView1.Enabled = true;
                showTrackingData.Enabled = true;
                updateIntervalTextBox.Enabled = true;
                oscUrl.Enabled = true;
                vrpnUrl.Enabled = true;
                if (backgroundWorker.IsBusy)
                {
                    backgroundWorker.CancelAsync();
                }
                if (oscWriter != null)
                {
                    oscWriter.Dispose();
                    oscWriter = null;
                }
            }
            state = newstate;
            if (state)
            {
                onoffButton.Text = "ON";
            }
            else
            {
                onoffButton.Text = "OFF";
            }
        }

        private bool initOsc()
        {
            string url = oscUrl.Text;
            try
            {
                UriBuilder uriB = new UriBuilder("http://" + url);
                if (uriB.Host == "" || uriB.Port == -1)
                {
                    throw new UriFormatException();
                }
                IPHostEntry iphe = Dns.GetHostEntry(uriB.Host);
                if (iphe.AddressList.Length < 1)
                {
                    statusLabel.Text = "OSC Hostname dns check failed";
                    return false;
                }
                else
                {
                    statusLabel.Text = "Connecting OSC to " + iphe.AddressList[0].ToString() + ":" + uriB.Port;
                }
                IPAddress targetIp = null;
                foreach (IPAddress ip in iphe.AddressList)
                {
                    if (ip.AddressFamily == AddressFamily.InterNetwork)
                    {
                        targetIp = ip;
                    }
                }
                if (targetIp == null)
                {
                    statusLabel.Text = "IPv6 not supported by OSC Library.";
                    return false;
                }
                oscWriter = new UdpWriter(targetIp.ToString(), uriB.Port);
                try
                {
                    oSCServersTableAdapter.Insert(url);
                    oSCServersTableAdapter.Fill(dataSet1.OSCServers);
                }
                catch (SQLiteException) { }
                Configuration c = configurationBindingSource.Current as Configuration;
                if (c != null)
                {
                    c.OscUrl = url;
                }
                return true;
            }
            catch (SocketException)
            {
                statusLabel.Text = "OSC Hostname not found.";
                return false;
            }
            catch (UriFormatException)
            {
                statusLabel.Text = "OSC url not in the right format. Try hostname:port.";
                return false;
            }
        }


        private bool initVrpn()
        {
            Connection c = Connection.GetConnectionByName(vrpnUrl.Text);
            if (c == null)
            {
                statusLabel.Text = "VRPN connection failed.";
                return false;
            }
            remoteHandlers = new List<RemoteHandler>();
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                DataGridViewCell test3 = row.Cells["Active"];
                if (row.Cells["Active"].Value is bool && (bool)row.Cells["Active"].Value == true)
                {
                    string type = row.Cells["Type"].Value as String;
                    if (type == null || type.Length == 0)
                    {
                        continue;
                    }
                    string vrpnName = row.Cells["VRPNName"].Value as String;
                    if (vrpnName == null || vrpnName.Length == 0)
                    {
                        continue;
                    }
                    string oscTarget = row.Cells["OSCTarget"].Value as String;
                    if (oscTarget == null || oscTarget.Length == 0)
                    {
                        continue;
                    }
                    RemoteHandler vo = RemoteHandlerFactory.Create(type, vrpnName, c);
                    if (vo == null) continue;
                    vo.DataCell = row.Cells["Data"];
                    vo.ShowTrackingData = showTrackingData.Checked;
                    vo.OscTarget = oscTarget;
                    vo.OscWriter = oscWriter;
                    remoteHandlers.Add(vo);
                }
            }
            statusLabel.Text = "VRPN Handlers initiated.";
            return true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void offStateMenu_Click(object sender, EventArgs e)
        {
            changeState(false);
        }

        private void onStateMenu_Click(object sender, EventArgs e)
        {
            changeState(true);
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            List<RemoteHandler> handlers = e.Argument as List<RemoteHandler>;
            int time = Int32.Parse(updateIntervalTextBox.Text);
            while (handlers != null && !backgroundWorker.CancellationPending)
            {
                foreach (RemoteHandler handler in handlers) {
                    handler.Update();
                }
                Thread.Sleep(time);
            }
        }

        private void onoffButton_ButtonClick(object sender, EventArgs e)
        {
            changeState(!state);
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            //entities.Dispose();
        }

        private void dataGridView1_RowValidated(object sender, DataGridViewCellEventArgs e)
        {
            sensorsTableAdapter.Update(this.dataSet1.Sensors);
        }
    }
}
